﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;

using tessnet2;

namespace Cryomancer.StarChart
{
	public class ChartOCRMaster : IChartOCRMaster
	{
		#region Members
		private Tesseract tess;

		#region Singleton stuff
		private static ChartOCRMaster theInstance;
		private static object         syncObj;
		#endregion

		#endregion

		#region Properties
		/// <summary>
		/// Gets an instance of the singleton ChartOCRMaster
		/// </summary>
		public static IChartOCRMaster Instance
		{
			get
			{
				return GetInstance();
			}
		}

		#endregion

		#region C'Tors and object lifetime code
		public ChartOCRMaster()
		{
			try
			{
				this.tess = new Tesseract();
				this.tess.Init("eng", "eng", false);
			}
			catch (Exception err)
			{
				throw new StarChartOCRInitializeException("Failed to initialize the Tesseract OCR engine.", err);
			}
		}

		static ChartOCRMaster()
		{
			syncObj = new object();
		}

		#endregion

		#region Methods

		#region Static Shortcut Methods
		/// <summary>
		/// Gets the EquitorialCoordinate of the chart.
		/// </summary>
		/// <param name="chart">A Bitmap representation of the chart</param>
		/// <returns>A coordinate</returns>
		public static EquitorialCoordinate GetCoordinate(Bitmap chart)
		{
			IChartOCRMaster instance = GetInstance();

			return instance.GetCoordinate(chart);
		}

		/// <summary>
		/// Gets the chart id.
		/// </summary>
		/// <param name="chart">A bitmap representation of the chart.</param>
		/// <returns>A string chart id.</returns>
		public static string GetChartID(Bitmap chart)
		{
			IChartOCRMaster instance = GetInstance();

			return instance.GetChartID(chart);
		}
		#endregion

		#region Private Worker Methods
		private static IChartOCRMaster GetInstance()
		{
			if (theInstance == null)
			{
				lock (syncObj)
				{
					if (theInstance == null)
					{
						theInstance = new ChartOCRMaster();
					}
				}
			}

			return theInstance;
		} 
		#endregion

		#endregion

		#region IChartOCRMaster Members

		EquitorialCoordinate IChartOCRMaster.GetCoordinate(Bitmap chart)
		{
			if (chart == null)
			{
				throw new ArgumentNullException("chart");
			}

			try
			{
				List<Word> words = tess.DoOCR(
						chart, 
						new Rectangle(
							(int)(chart.Width  * 0.25),
							0,
							(int)(chart.Width  * 0.50),
							(int)(chart.Height * 0.10)));

				//There should be at LEAST 2 words.  Grab the last two...
				if (words.Count < 2)
				{
					throw new Exception("Did not find the coordinates on the chart");
				}

				string ra  = words[words.Count - 2].Text;
				string dec = words[words.Count - 1].Text;

				//the RA value has the J2000 in it.  Just remove it.
				ra = ra.Replace("(2000)", String.Empty);

				//Now create the EqCoord.
				EquitorialCoordinate retVal = EquitorialCoordinate.FromMinSecFormat(ra, dec);
				return retVal;
			}
			catch (Exception err)
			{
				throw new StarChartOCRRecognizeException("Failed to find the coordinate.", err);
			}
		}

		string IChartOCRMaster.GetChartID(Bitmap chart)
		{
			try
			{
				List<Word> words = tess.DoOCR(
						chart, 
						new Rectangle(
							(int)(chart.Width  * 0.83),
							(int)(chart.Height * 0.076),
							(int)(chart.Width  * 0.15),
							(int)(chart.Height * 0.04)));

				if (words.Count == 0)
				{
					throw new Exception("Did not find the chart id.");
				}

				return words[0].Text;
			}
			catch (Exception err)
			{
				throw new StarChartOCRRecognizeException("Failed to find the chart id.", err);
			}
		}

		#endregion
	}

	public interface IChartOCRMaster
	{
		EquitorialCoordinate GetCoordinate(Bitmap chart);
		string               GetChartID(Bitmap chart);
	}


}
